package com.ruoyi.assemble.flow.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.didiglobal.turbo.engine.common.FlowDeploymentStatus;
import com.didiglobal.turbo.engine.dao.ProcessInstanceDAO;
import com.didiglobal.turbo.engine.engine.ProcessEngine;
import com.didiglobal.turbo.engine.entity.FlowDeploymentPO;
import com.didiglobal.turbo.engine.entity.FlowInstancePO;
import com.didiglobal.turbo.engine.model.InstanceData;
import com.didiglobal.turbo.engine.param.*;
import com.didiglobal.turbo.engine.result.*;
import com.ruoyi.assemble.flow.enums.FlowModuleStatusEnum;
import com.ruoyi.assemble.flow.pojo.request.GetFlowInstanceListRequest;
import com.ruoyi.assemble.flow.pojo.response.BaseResponse;
import com.ruoyi.assemble.flow.pojo.response.FlowModuleListResponse;
import com.ruoyi.assemble.flow.pojo.response.FlowModuleResponse;
import com.ruoyi.assemble.flow.util.Constant;
import com.ruoyi.assemble.flow.util.EntityBuilder;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * @author rick
 * @Date 2022/4/6 14:08
 * 先来了解一下常见的请假过程：
 * 小T是桔厂的员工，本周三有事想请假，提交了一个请假流程，根据公司规定，3天及以内的假期需要直属领导审批，超过3天需要间接领导审批。
 * <3
 * --->  用户节点（直属领导审批）--->
 * 开始节点 ---> 用户节点（输入请假天数）--->   排他网关                                 结束节点
 * --->  用户节点（间接领导审批）--->
 * >=3
 */
@Service
public class LeaveServiceImpl {
    private static final Logger LOGGER = LoggerFactory.getLogger(LeaveServiceImpl.class);

    @Resource
    private ProcessEngine processEngine;

    @Resource
    private ProcessInstanceDAO processInstanceDAO;

    private CreateFlowParam createFlowParam;
    private CreateFlowResult createFlowResult;
    private UpdateFlowResult updateFlowResult;
    private DeployFlowResult deployFlowResult;

    public void run() {
        LOGGER.info("LeaveSOP Demo run:");

        LOGGER.info("LeaveSOP definition:");

        createFlow();

        updateFlow();

        deployFlow();

        LOGGER.info("LeaveSOP runtime:");

        ////startProcessToEnd();
    }

    public void createFlow() {
        createFlowParam = new CreateFlowParam(Constant.tenant, Constant.caller);
        createFlowParam.setFlowKey("person_time");
        createFlowParam.setFlowName("请假SOP");
        createFlowParam.setRemark("demo");
        createFlowParam.setOperator(Constant.operator);
        createFlowResult = processEngine.createFlow(createFlowParam);
        LOGGER.info("createFlow.||createFlowResult={}", createFlowResult);
    }

    public void updateFlow() {
        UpdateFlowParam updateFlowParam = new UpdateFlowParam(Constant.tenant, Constant.caller);
        updateFlowParam.setFlowModel(EntityBuilder.buildLeaveFlowModelStr());
        updateFlowParam.setFlowModuleId(createFlowResult.getFlowModuleId());
        updateFlowResult = processEngine.updateFlow(updateFlowParam);
        LOGGER.info("updateFlow.||updateFlowResult={}", updateFlowResult);
    }

    public void deployFlow() {
        DeployFlowParam param = new DeployFlowParam(Constant.tenant, Constant.caller);
        param.setFlowModuleId(createFlowResult.getFlowModuleId());
        deployFlowResult = processEngine.deployFlow(param);
        LOGGER.info("deployFlow.||deployFlowResult={}", deployFlowResult);
    }

    /*public void startProcessToEnd() {
        StartProcessResult startProcess = startProcess();
        CommitTaskResult commitTaskResult = inputTime(startProcess);
        RollbackTaskResult rollbackTaskResult = rollbackToInputTime(commitTaskResult);
        CommitTaskResult result = inputTimeAgain(rollbackTaskResult);
        commitCompleteProcess(result);
    }*/

    // 用户拉起请假sop
    public StartProcessResult startProcess(StartProcessParam startProcessParam) {
        ////StartProcessParam startProcessParam = new StartProcessParam();
        ////startProcessParam.setFlowDeployId(deployFlowResult.getFlowDeployId());
        List<InstanceData> variables = new ArrayList<>();
        variables.add(new InstanceData("user_name", "请假人"));
        startProcessParam.setVariables(variables);
        StartProcessResult startProcessResult = processEngine.startProcess(startProcessParam);

        LOGGER.info("startProcess.||startProcessResult={}", startProcessResult);
        return startProcessResult;
    }

    // 输入请假天数
    public CommitTaskResult inputTime(StartProcessResult startProcessResult) {
        CommitTaskParam commitTaskParam = new CommitTaskParam();
        commitTaskParam.setFlowInstanceId(startProcessResult.getFlowInstanceId());
        commitTaskParam.setTaskInstanceId(startProcessResult.getActiveTaskInstance().getNodeInstanceId());
        List<InstanceData> variables = new ArrayList<>();
        variables.add(new InstanceData("user_name", "请假人名字"));
        variables.add(new InstanceData("n", 1));
        commitTaskParam.setVariables(variables);

        CommitTaskResult commitTaskResult = processEngine.commitTask(commitTaskParam);
        LOGGER.info("inputTime.||commitTaskResult={}", commitTaskResult);
        return commitTaskResult;
    }

    // 请假撤回
    public RollbackTaskResult rollbackToInputTime(CommitTaskResult commitTaskResult) {
        RollbackTaskParam rollbackTaskParam = new RollbackTaskParam();
        rollbackTaskParam.setFlowInstanceId(commitTaskResult.getFlowInstanceId());
        rollbackTaskParam.setTaskInstanceId(commitTaskResult.getActiveTaskInstance().getNodeInstanceId());
        RollbackTaskResult rollbackTaskResult = processEngine.rollbackTask(rollbackTaskParam);

        LOGGER.info("rollbackToInputTime.||rollbackTaskResult={}", rollbackTaskResult);
        return rollbackTaskResult;
    }

    // 填写请假天数
    public CommitTaskResult inputTimeAgain(RollbackTaskResult rollbackTaskResult) {
        CommitTaskParam commitTaskParam = new CommitTaskParam();
        commitTaskParam.setFlowInstanceId(rollbackTaskResult.getFlowInstanceId());
        commitTaskParam.setTaskInstanceId(rollbackTaskResult.getActiveTaskInstance().getNodeInstanceId());
        List<InstanceData> variables = new ArrayList<>();
        variables.add(new InstanceData("user_name", "请假人名字"));
        variables.add(new InstanceData("n", 2));
        commitTaskParam.setVariables(variables);

        CommitTaskResult commitTaskResult = processEngine.commitTask(commitTaskParam);
        LOGGER.info("inputTimeAgain.||commitTaskResult={}", commitTaskResult);
        return commitTaskResult;
    }

    // BadCase：已完成流程，继续执行流程会失败。
    public CommitTaskResult commitCompleteProcess(CommitTaskResult commitTaskResult) {
        CommitTaskParam commitTaskParam = new CommitTaskParam();
        commitTaskParam.setFlowInstanceId(commitTaskResult.getFlowInstanceId());
        commitTaskParam.setTaskInstanceId(commitTaskResult.getActiveTaskInstance().getNodeInstanceId());
        List<InstanceData> variables = new ArrayList<>();
        variables.add(new InstanceData("user_name", "请假人名字"));
        variables.add(new InstanceData("n", 4));
        commitTaskParam.setVariables(variables);

        CommitTaskResult result = processEngine.commitTask(commitTaskParam);
        LOGGER.info("inputTimeBadCase.||CommitTaskResult={}", result);
        return result;
    }

    /* 新加 2023年2月26日 yuqhadd*/
    /**
     * 查询流程实例列表
     *
     * @param getFlowInstanceListRequest 查询流程实例列表参数
     * @return 查询流程实例
     */
    public BaseResponse getFlowOrderList(GetFlowInstanceListRequest getFlowInstanceListRequest) {

        Page<FlowInstancePO> page = buildGetFlowInstanceListPage(getFlowInstanceListRequest);
        QueryWrapper<FlowInstancePO> queryWrapper = buildGetFlowModuleListQueryWrapper(getFlowInstanceListRequest);
        IPage<FlowInstancePO> pageRes = processInstanceDAO.page(page, queryWrapper);
        //BeanUtils.copyProperties(pageRes, pageRes);
        System.out.println(BaseResponse.make(pageRes));
        return BaseResponse.make(pageRes);
    }

    private Page<FlowInstancePO> buildGetFlowInstanceListPage(GetFlowInstanceListRequest getFlowInstanceListRequest) {
        Page<FlowInstancePO> page = new Page<>();
        if (getFlowInstanceListRequest.getSize() != null && getFlowInstanceListRequest.getCurrent() != null) {
            page.setCurrent(getFlowInstanceListRequest.getCurrent());
            page.setSize(getFlowInstanceListRequest.getSize());
        }
        return page;
    }
    
    private QueryWrapper<FlowInstancePO> buildGetFlowModuleListQueryWrapper(GetFlowInstanceListRequest getFlowInstanceListRequest) {
        QueryWrapper<FlowInstancePO> queryWrapper = new QueryWrapper<>();
        if (StringUtils.isNotBlank(getFlowInstanceListRequest.getFlowModuleId())) {
            queryWrapper.eq("flow_module_id", getFlowInstanceListRequest.getFlowModuleId());
        }
        if (StringUtils.isNotBlank(getFlowInstanceListRequest.getFlowName())) {
            queryWrapper.like("flow_name", getFlowInstanceListRequest.getFlowName());
        }
        if (StringUtils.isNotBlank(getFlowInstanceListRequest.getFlowDeployId())) {
            queryWrapper.eq("flow_module_id", getFlowInstanceListRequest.getFlowDeployId());
        }
        queryWrapper.orderByDesc("modify_time");
        return queryWrapper;
    }

    private QueryWrapper<FlowDeploymentPO> buildCountFlowDeployQueryWrapper(String flowModuleId) {
        QueryWrapper<FlowDeploymentPO> flowDeployQuery = new QueryWrapper<>();
        flowDeployQuery.eq("flow_module_id", flowModuleId);
        flowDeployQuery.eq("status", FlowDeploymentStatus.DEPLOYED);
        return flowDeployQuery;
    }

    /**
     * 查询流程实例列表-待办
     *
     * @param getFlowInstanceListRequest 查询流程实例列表参数
     * @return 查询流程实例
     */
    public BaseResponse getFlowOrderList1(GetFlowInstanceListRequest getFlowInstanceListRequest) {

        Page<FlowInstancePO> page = buildGetFlowInstanceListPage(getFlowInstanceListRequest);
        QueryWrapper<FlowInstancePO> queryWrapper = buildGetFlowModuleListQueryWrapper(getFlowInstanceListRequest);
        IPage<FlowInstancePO> pageRes = processInstanceDAO.page(page, queryWrapper);
        //BeanUtils.copyProperties(pageRes, pageRes);
        System.out.println(BaseResponse.make(pageRes));
        return BaseResponse.make(pageRes);
    }
}
